package com.zian.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zian.common.CommonConstant;
import com.zian.context.BaseContext;
import com.zian.domain.dto.CategoryDTO;
import com.zian.domain.po.SysGoodsCategory;
import com.zian.domain.po.SysGoodsInfo;
import com.zian.domain.vo.CategoryVO;
import com.zian.enums.IsDeletedEnum;
import com.zian.exception.BadRequestException;
import com.zian.exception.BizIllegalException;
import com.zian.exception.DbException;
import com.zian.mapper.SysGoodsCategoryMapper;
import com.zian.mapper.SysGoodsInfoMapper;
import com.zian.service.ISysGoodsCategoryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zian.utils.RedisUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author
 * @since 2024-09-08
 */
@Service
@RequiredArgsConstructor
public class SysGoodsCategoryServiceImpl extends ServiceImpl<SysGoodsCategoryMapper, SysGoodsCategory> implements ISysGoodsCategoryService {

    private final SysGoodsInfoMapper goodsInfoMapper;

    private final RedisUtils redisUtils;

    @Override
    public List<CategoryVO> getTopCategory() {
        List<SysGoodsCategory> list = lambdaQuery().eq(SysGoodsCategory::getParentId, CommonConstant.CATEGORY_ROOT_ID).list();
        if (CollUtil.isEmpty(list)) return CollUtil.empty(List.class);
        return BeanUtil.copyToList(list, CategoryVO.class);
    }

    @Override
    public List<Tree<Long>> getChildrenCategory(Long id) {
        List<SysGoodsCategory> goodsCategoryList = list();
        List<Long> childrenIds = new ArrayList<>();
        getChildrenIds(childrenIds, goodsCategoryList, id);
        if (CollUtil.isEmpty(childrenIds)) return CollUtil.empty(List.class);

        // 去重
        Set<Long> ids = new HashSet<>(childrenIds);
        if (ids.isEmpty()) return CollUtil.empty(List.class);

        // 根据 CategoryRank 对集合进行排序，从大到小排序
        goodsCategoryList = goodsCategoryList.stream()
                .sorted((o1, o2) -> o2.getCategoryRank() - o1.getCategoryRank())
                .filter(item -> ids.contains(item.getId()) && !item.getId().equals(id))
                .collect(Collectors.toList());
        return generateTree(goodsCategoryList, id);
    }

    @Override
    public List<Tree<Long>> queryCategory() {
        Serializable categoryCache = redisUtils.getCacheObject("categoryCache");
        if (categoryCache == null) {
            List<SysGoodsCategory> goodsCategoryList = list();
            redisUtils.setCacheObject("categoryCache", (Serializable) goodsCategoryList);
            // 根据 CategoryRank 对集合进行排序，从大到小排序
            goodsCategoryList = goodsCategoryList.stream()
                    .sorted((o1, o2) -> o2.getCategoryRank() - o1.getCategoryRank())
                    .collect(Collectors.toList());

            return generateTree(goodsCategoryList, CommonConstant.CATEGORY_ROOT_ID);
        }

        List<SysGoodsCategory> goodsCategoryList = (List<SysGoodsCategory>) categoryCache;
        // 根据 CategoryRank 对集合进行排序，从大到小排序
        goodsCategoryList = goodsCategoryList.stream()
                .sorted((o1, o2) -> o2.getCategoryRank() - o1.getCategoryRank())
                .collect(Collectors.toList());
        return generateTree(goodsCategoryList, CommonConstant.CATEGORY_ROOT_ID);
    }

    public List<Tree<Long>> generateTree(List<SysGoodsCategory> goodsCategoryList, Long id) {
        if (CollUtil.isEmpty(goodsCategoryList)) return CollUtil.empty(List.class);
        List<TreeNode<Long>> treeNodeList = goodsCategoryList.stream().map(item -> {
            TreeNode<Long> treeNode = new TreeNode<>();
            treeNode.setId(item.getId());
            treeNode.setName(item.getCategoryName());
            treeNode.setParentId(item.getParentId());

            // 添加额外信息
            Map<String, Object> extra = new HashMap<>();
            extra.put("categoryRank", item.getCategoryRank());
            extra.put("createTime", item.getCreateTime());
            extra.put("icon", item.getIcon());
            treeNode.setExtra(extra);
            return treeNode;
        }).collect(Collectors.toList());

        TreeNodeConfig config = new TreeNodeConfig();
        // 默认的 nameKey 是 name ，所以这里需要修改
        config.setNameKey("categoryName");
        List<Tree<Long>> vos = TreeUtil.build(treeNodeList, id, config, (treeNode, tree) -> {
            tree.setId(treeNode.getId());
            tree.setParentId(treeNode.getParentId());
            tree.putExtra("categoryName", treeNode.getName());
            // 添加额外信息
            Map<String, Object> extra = treeNode.getExtra();
            tree.putExtra("categoryRank", extra.get("categoryRank"));
            tree.putExtra("createTime", extra.get("createTime"));
            tree.putExtra("icon", extra.get("icon"));
        });
        return vos;
    }

    @Override// 删除缓存，并且删除所有缓存
    public void addCategory(CategoryDTO dto) {
        Long currentId = BaseContext.getCurrentId();
        SysGoodsCategory one = lambdaQuery().eq(SysGoodsCategory::getCategoryName, dto.getCategoryName()).one();
        if (one != null) throw new BizIllegalException("分类名称已存在");
        List<Long> ancestors = dto.getAncestors();
        List<Integer> dbAncestors = new ArrayList<>();
        dbAncestors.add(0);
        Long parentId = null;
        // 第一种情况 修改为 根节点 ancestors 是第一个空集合 ， parentId 为 0 ， ancestors 为 [0]
        if (CollUtil.isEmpty(ancestors)) {
        } else if (ancestors.size() == 1) {
            // 第二种情况 修改二级节点  ancestors 只有的元素  , parentId 为集合中的第一个元素 ， ancestors 为 [0,ancestors中的所有元素]
            dbAncestors.add(ancestors.get(0).intValue());
            parentId = ancestors.get(0);
        } else if (ancestors.size() == 2) {
            // 第三种情况 修改为三级以及三级一下的节点  ancestors 有 2 个元素以及 以上 ， parentId 为集合的最后一个元素 ， [0, ancestors中的所有元素]
            CollUtil.addAll(dbAncestors, ancestors);
            parentId = ancestors.get(ancestors.size() - 1);
        } else {
            throw new BizIllegalException("分类层不能超过 3 层");
        }

        // 查询父级分类是否存在
        if (parentId != null) {
            SysGoodsCategory category = getById(parentId);
            if (category == null) throw new DbException("父级分类不存在");
        } else {
            parentId = 0L;
        }

        SysGoodsCategory category = new SysGoodsCategory();
        category.setCategoryName(dto.getCategoryName());
        category.setCategoryRank(dto.getCategoryRank());
        category.setIcon(dto.getIcon());
        category.setIsDeleted(IsDeletedEnum.NO);
        category.setAncestors(dbAncestors);
        category.setParentId(parentId);
        category.setCreateUser(currentId);
        category.setUpdateUser(currentId);
        if (!save(category)) throw new DbException("新增分类失败");
        redisUtils.deleteObject("categoryCache");


    }

    @Override
    public void updateCategory(CategoryDTO dto) {
        Long currentId = BaseContext.getCurrentId();

        SysGoodsCategory goodsCategory = getById(dto.getId());
        if (goodsCategory == null) {
            throw new BadRequestException("分类不存在");
        }
        List<Long> ancestors = dto.getAncestors();
        List<Integer> dbAncestors = new ArrayList<>();
        dbAncestors.add(0);

        // 第一种情况 修改为 根节点 ancestors 是第一个空集合 ， parentId 为 0 ， ancestors 为 [0]
        if (CollUtil.isEmpty(ancestors)) {
            goodsCategory.setParentId(0L);
        } else if (ancestors.size() == 1) {
            // 第二种情况 修改二级节点  ancestors 只有的元素  , parentId 为集合中的第一个元素 ， ancestors 为 [0,ancestors中的所有元素]
            goodsCategory.setParentId(ancestors.get(0));
            dbAncestors.add(ancestors.get(0).intValue());
        } else if (ancestors.size() == 2) {
            // 第三种情况 修改为三级以及三级一下的节点  ancestors 有 2 个元素以及 以上 ， parentId 为集合的最后一个元素 ， [0, ancestors中的所有元素]
            goodsCategory.setParentId(ancestors.get(ancestors.size() - 1));
            CollUtil.addAll(dbAncestors, ancestors);
        } else {
            throw new BizIllegalException("分类层不能超过 3 层");
        }

        goodsCategory.setAncestors(dbAncestors);
        goodsCategory.setIcon(dto.getIcon());
        goodsCategory.setCategoryName(dto.getCategoryName());
        goodsCategory.setCategoryRank(dto.getCategoryRank());
        goodsCategory.setUpdateUser(currentId);
        boolean b = updateById(goodsCategory);
        if (!b) throw new DbException("修改分类失败");
        redisUtils.deleteObject("categoryCache");
    }

    @Override
    @Transactional
    @CacheEvict(value = "categoryCache", allEntries = true) // 删除缓存，并且删除所有缓存
    public void deleteCategoryById(Long id, Boolean flag) {
        Long currentId = BaseContext.getCurrentId();
        SysGoodsCategory category = getById(id);
        if (category == null) throw new BadRequestException("分类不存在");

        List<SysGoodsCategory> goodsCategoryList = list();

        List<Long> childrenIds = new ArrayList<>();
        // 利用递归收集所有需要删除的分类id
        getChildrenIds(childrenIds, goodsCategoryList, id);

        Set<Long> ids = new HashSet<>(childrenIds);
        if (CollUtil.isNotEmpty(ids) && !flag) throw new BizIllegalException("请先删除子分类，或者强制删除");
        ids.add(id); // 添加当前id

        // 判断当前分类下是否有商品
        SysGoodsInfo sysGoodsInfo = goodsInfoMapper.selectOne(
                Wrappers.<SysGoodsInfo>lambdaQuery()
                        .in(SysGoodsInfo::getGoodsCategoryId, ids)
        );
        if (sysGoodsInfo != null) throw new BizIllegalException("该分类或者子类下有商品，无法删除");

        boolean b = lambdaUpdate()
                .in(SysGoodsCategory::getId, ids)
                .set(SysGoodsCategory::getIsDeleted, IsDeletedEnum.YES)
                .set(SysGoodsCategory::getUpdateTime, LocalDateTime.now())
                .set(SysGoodsCategory::getUpdateUser, currentId)
                .update();
        if (!b) throw new DbException("删除分类失败");
        redisUtils.deleteObject("categoryCache");
    }

    /**
     * 获取子级id
     *
     * @param goodsCategoryList 分类集合
     * @param id                父级id
     */
    private void getChildrenIds(List<Long> childrenIds, List<SysGoodsCategory> goodsCategoryList, Long id) {
        List<SysGoodsCategory> list = goodsCategoryList
                .stream()
                .filter(item -> item.getParentId().equals(id))
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(list)) return;
        childrenIds.addAll(list.stream().map(SysGoodsCategory::getId).collect(Collectors.toList()));
        list.forEach(
                item -> {
                    childrenIds.add(item.getId());
                    getChildrenIds(childrenIds, goodsCategoryList, item.getId());
                }
        );

    }


    @Override
    public SysGoodsCategory getCategoryById(Long id) {
        if (id == null) throw new BadRequestException("参数错误");
        SysGoodsCategory category = getById(id);
        System.out.println("category = " + category);
        if (category == null) throw new BadRequestException("分类不存在");
        return category;
    }
}
